﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;

namespace TMS
{
    public class ErrorXMLManager: XMLBaseManager
    {
        private static ErrorXMLManager _instancia;
        public static ErrorXMLManager getInstancia()
        {
            if (_instancia == null)
            {
                _instancia = new ErrorXMLManager();
            }
            return _instancia;
        }
        private ErrorXMLManager()
        {
            nombreRoot = "Errores";
            nombreArchivo = nombreRoot + ".xml";
        }

        public void addError(Error pError)
        {
            XDocument xDoc = loadDoc(); //Carga el documento.
            XElement errores = xDoc.Root; //Obtiene la raiz del documento XML.
            XElement err = new XElement("Error");
            err.SetAttributeValue("Id", pError.Id);
            err.SetElementValue("Aplicacion", "" + pError.Aplicacion.Id);
            err.SetElementValue("Modulo", "" + pError.Modulo.Id);
            err.SetElementValue("Descripcion", pError.Descripcion);
            err.SetElementValue("Estado", pError.Estado.ToString());
            err.SetElementValue("Importancia", pError.Importancia.ToString());
            err.SetElementValue("Usuario", "" + pError.Usuario.NroUsuario);
            err.SetElementValue("FechaCreado", pError.FechaCreado.ToString());
            err.SetElementValue("FechaCerrado", "");
            errores.Add(err);
            saveDoc(xDoc);
        }
        public void updateError(Error pError)
        {
            XDocument xDoc = loadDoc();
            XElement err = xDoc.Root.Elements().Single(e => long.Parse(e.Attribute("Id").Value) == pError.Id);
            //Si el usuario es el creador del error o si es un administrador entonces puede modificar el error o cerrarlo.
            if (pError.Usuario.NroUsuario == long.Parse(err.Element("Usuario").Value) || UsuarioXMLManager.getInstancia().getTipoUsuario(pError.Usuario.NroUsuario) == "" + tipoUsuario.Administrador)
            {
                /*err.SetElementValue("Aplicacion", "" + pError.Aplicacion.Id);
                err.SetElementValue("Modulo", "" + pError.Modulo.Id);*/
                err.SetElementValue("Descripcion", pError.Descripcion);
                err.SetElementValue("Estado", pError.Estado.ToString());
                err.SetElementValue("Importancia", pError.Importancia.ToString());
                err.SetElementValue("Usuario", "" + pError.Usuario.NroUsuario);
                //Si el error fue cerrado...
                if (pError.Estado == tipoEstado.Cerrado)
                {
                    //Se almacena la fecha de cierre.
                    err.SetElementValue("FechaCerrado", pError.FechaCerrado.ToString());
                }
                saveDoc(xDoc);
            }
        }
        public void cerrarError(Error pError)
        {
            /*
             * El siguiente codigo cierra un error, asignandole la fecha de cierre que tiene como atributo
             * la instancia de Error que se recibe como parametro.
             */ 
            XDocument xDoc = loadDoc();
            XElement err = xDoc.Root.Elements().Single(e => (long)e.Attribute("Id") == pError.Id);
            if (err.Element("FechaCerrado").Value == "")
            {
                err.SetElementValue("FechaCerrado", pError.FechaCerrado.ToString());
            }
            saveDoc(xDoc);
        }
        
        /*  */
        public void removeErrorById(long pId) //Elimina cualquier elemento principal por el Id del elemento.
        {
            /* 
             * Primero elimina todos los comentarios referentes al error utilizando el metodo apropiado del manejador de XML 
             * de ComentarioError.
             */
            ComentarioErrorXMLManager.getInstancia().removeComentsByIdError(pId);
            /*
             * Luego elimina el error almacenado en el documento XML por su Id.
             */
            this.removeById(pId);
        }

        public void removeErrorsByModId(long pModId) //Elimina todos los errores del documento XML relacionados con un modulo por su Id.
        { 
            XDocument xDoc = loadDoc(); // Carga el documento Errores.xml
            /* 
             * Realiza iteraciones por una lista de todos los errores almacenados en el documento cuyo elemento "Modulo"
             * contenga un valor igual al Id del modulo que se recibe como parametro y utiliza el Id de cada uno los elementos
             * encontrados para eliminarlos, utilizando el metodo removeErrorById.
             */ 
            foreach (XElement xe in xDoc.Root.Elements().Where(e => long.Parse(e.Element("Modulo").Value) == pModId))
            {
                this.removeErrorById(long.Parse(xe.Attribute("Id").Value));
            }
            saveDoc(xDoc); // Guarda los cambios en el documento.
        }
        public List<ComentarioError> getListComments(long pId)
        {
            /*
             * Obtiene una lista de comentarios relacionados con el error cuyo Id se recibe como parametro, a traves del metodo
             * correspondiente que se encuentra en el manejador XML de ComentarioError.
             */ 
            return ComentarioErrorXMLManager.getInstancia().getComentariosByIdError(pId);
        }
        public List<Error> getListByUserId(long pUsId)
        {
            /*
             * Devuelve una lista de errores por el Id del usuario que los creo.
             */ 
            List<Error> errLst = new List<Error>();
            XDocument xDoc = loadDoc();
            try
            {
                foreach (XElement xEl in xDoc.Root.Elements().Where(e => long.Parse(e.Element("Usuario").Value) == pUsId))
                {
                    Error err = new Error();
                    err.Id = long.Parse(xEl.Attribute("Id").Value);
                    err.Aplicacion = AplicacionXMLManager.getInstancia().getAplicacionById(long.Parse(xEl.Element("Aplicacion").Value));
                    err.Modulo = ModuloXMLManager.getInstancia().getModuloById(long.Parse(xEl.Element("Modulo").Value));
                    err.Descripcion = "" + xEl.Element("Descripcion").Value;
                    err.Estado = (tipoEstado)Enum.Parse(typeof(tipoEstado), "" + xEl.Element("Estado").Value);
                    err.Importancia = (tipoImportancia)Enum.Parse(typeof(tipoImportancia), "" + xEl.Element("Importancia").Value);
                    err.Usuario = UsuarioXMLManager.getInstancia().getUsuarioById(long.Parse(xEl.Element("Usuario").Value));
                    err.FechaCreado = DateTime.Parse(xEl.Element("FechaCreado").Value);
                    //Si tiene fecha de cerrado asignada...
                    if (xEl.Element("FechaCerrado").Value != "")
                    {
                        err.FechaCerrado = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                    }
                    errLst.Add(err);
                }
            }
            catch (InvalidOperationException)
            { 
                
            }
            return errLst;
        }
        public Error getErrorById(long errId)
        {
            /*
             * Devuelve una instancia de Error con los datos correspondientes al Id suministrado como parrametro.
             */ 
            Error err = new Error();
            XDocument xDoc = loadDoc();
            try
            {
                XElement xEl = xDoc.Root.Elements().Single(e => long.Parse(e.Attribute("Id").Value) == errId);
                err.Id = long.Parse(xEl.Attribute("Id").Value);
                err.Aplicacion = AplicacionXMLManager.getInstancia().getAplicacionById(long.Parse(xEl.Element("Aplicacion").Value));
                err.Modulo = ModuloXMLManager.getInstancia().getModuloById(long.Parse(xEl.Element("Modulo").Value));
                err.Descripcion = "" + xEl.Element("Descripcion").Value;
                err.Estado = (tipoEstado)Enum.Parse(typeof(tipoEstado), "" + xEl.Element("Estado").Value);
                err.Importancia = (tipoImportancia)Enum.Parse(typeof(tipoImportancia), "" + xEl.Element("Importancia").Value);
                err.Usuario = UsuarioXMLManager.getInstancia().getUsuarioById(long.Parse(xEl.Element("Usuario").Value));
                err.FechaCreado = DateTime.Parse(xEl.Element("FechaCreado").Value);
                //Si tiene fecha de cerrado asignada...
                if (xEl.Element("FechaCerrado").Value != "")
                {
                    err.FechaCerrado = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                }
            }
            catch (InvalidOperationException)
            {
                err = null;
            }
            return err;
        }
        public List<Error> getListByFechaCerrado(DateTime fecha1, DateTime fecha2)
        {
            /*
             * Devuelve una lista de errores CERRADOS dentro del rango de fechas dados por los 
             * parametros fecha1 y fecha2.
             */
            //Se revisa el orden de las fechas que se reciben como parametro.
            DateTime fechaIni = new DateTime();
            DateTime fechaFin = new DateTime();
            if (fecha1 < fecha2)
            {
                fechaIni = fecha1;
                fechaFin = fecha2;
            }
            else if (fecha1 > fecha2)
            {
                fechaIni = fecha2;
                fechaFin = fecha1;
            }
            List<Error> errLst = new List<Error>();
            XDocument xDoc = loadDoc();
            try
            {
                foreach (XElement xEl in xDoc.Root.Elements())
                {
                    if (xEl.Element("FechaCerrado").Value != "" && xEl.Element("Estado").Value == "Cerrado")
                    {
                        DateTime fecha = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                        if (fecha >= fechaIni && fecha <= fechaFin)
                        {
                            Error err = new Error();
                            err.Id = long.Parse(xEl.Attribute("Id").Value);
                            err.Aplicacion = AplicacionXMLManager.getInstancia().getAplicacionById(long.Parse(xEl.Element("Aplicacion").Value));
                            err.Modulo = ModuloXMLManager.getInstancia().getModuloById(long.Parse(xEl.Element("Modulo").Value));
                            err.Descripcion = "" + xEl.Element("Descripcion").Value;
                            err.Estado = (tipoEstado)Enum.Parse(typeof(tipoEstado), "" + xEl.Element("Estado").Value);
                            err.Importancia = (tipoImportancia)Enum.Parse(typeof(tipoImportancia), "" + xEl.Element("Importancia").Value);
                            err.Usuario = UsuarioXMLManager.getInstancia().getUsuarioById(long.Parse(xEl.Element("Usuario").Value));
                            err.FechaCreado = DateTime.Parse(xEl.Element("FechaCreado").Value);
                            err.FechaCerrado = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                            errLst.Add(err);
                        }
                    }
                }
            }
            catch (InvalidOperationException)
            {
                errLst = null;
            }
            return errLst;
        }
        public List<Error> getListByFechaCreado(DateTime fecha1, DateTime fecha2)
        {
            /*
             * Devuelve una lista de errores CREADOS dentro del rango de fechas dados por los 
             * parametros fecha1 y fecha2.
             */
            //Se revisa el orden de las fechas que se reciben como parametro.
            DateTime fechaIni = new DateTime();
            DateTime fechaFin = new DateTime();
            if (fecha1 < fecha2)
            {
                fechaIni = fecha1;
                fechaFin = fecha2;
            }
            else if (fecha1 > fecha2)
            {
                fechaIni = fecha2;
                fechaFin = fecha1;
            }
            List<Error> errLst = new List<Error>();
            XDocument xDoc = loadDoc();
            try
            {
                foreach (XElement xEl in xDoc.Root.Elements())
                {
                    if (xEl.Element("FechaCreado").Value != "")
                    {
                        DateTime fecha = DateTime.Parse(xEl.Element("FechaCreado").Value);
                        if (fecha >= fechaIni && fecha <= fechaFin)
                        {
                            Error err = new Error();
                            err.Id = long.Parse(xEl.Attribute("Id").Value);
                            err.Aplicacion = AplicacionXMLManager.getInstancia().getAplicacionById(long.Parse(xEl.Element("Aplicacion").Value));
                            err.Modulo = ModuloXMLManager.getInstancia().getModuloById(long.Parse(xEl.Element("Modulo").Value));
                            err.Descripcion = "" + xEl.Element("Descripcion").Value;
                            err.Estado = (tipoEstado)Enum.Parse(typeof(tipoEstado), "" + xEl.Element("Estado").Value);
                            err.Importancia = (tipoImportancia)Enum.Parse(typeof(tipoImportancia), "" + xEl.Element("Importancia").Value);
                            err.Usuario = UsuarioXMLManager.getInstancia().getUsuarioById(long.Parse(xEl.Element("Usuario").Value));
                            err.FechaCreado = DateTime.Parse(xEl.Element("FechaCreado").Value);
                            if (xEl.Element("FechaCerrado").Value != "")
                            {
                                err.FechaCerrado = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                            }
                            errLst.Add(err);
                        }
                    }
                }
            }
            catch (InvalidOperationException)
            {
                errLst = null;
            }
            return errLst;
        }
        public List<Error> getListByImportancia(string pImpor)
        {
            /*
             * Devuelve una lista de errores con el grado de importancia indicado por el parametro.
             */
            List<Error> errLst = new List<Error>();
            XDocument xDoc = loadDoc();
            try
            {
                foreach (XElement xEl in xDoc.Root.Elements())
                {
                    if (xEl.Element("Importancia").Value == pImpor)
                    {
                            Error err = new Error();
                            err.Id = long.Parse(xEl.Attribute("Id").Value);
                            err.Aplicacion = AplicacionXMLManager.getInstancia().getAplicacionById(long.Parse(xEl.Element("Aplicacion").Value));
                            err.Modulo = ModuloXMLManager.getInstancia().getModuloById(long.Parse(xEl.Element("Modulo").Value));
                            err.Descripcion = "" + xEl.Element("Descripcion").Value;
                            err.Estado = (tipoEstado)Enum.Parse(typeof(tipoEstado), "" + xEl.Element("Estado").Value);
                            err.Importancia = (tipoImportancia)Enum.Parse(typeof(tipoImportancia), "" + xEl.Element("Importancia").Value);
                            err.Usuario = UsuarioXMLManager.getInstancia().getUsuarioById(long.Parse(xEl.Element("Usuario").Value));
                            err.FechaCreado = DateTime.Parse(xEl.Element("FechaCreado").Value);
                            if (xEl.Element("FechaCerrado").Value != "")
                            {
                                err.FechaCerrado = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                            }
                            errLst.Add(err);
                        }
                    }
                }
            
            catch (InvalidOperationException)
            {
                errLst = null;
            }
            return errLst;
        }
        public List<Error> getListByEstado(string pEstado)
        {
            /*
             * Devuelve una lista de errores con el grado de importancia indicado por el parametro.
             */
            List<Error> errLst = new List<Error>();
            XDocument xDoc = loadDoc();
            try
            {
                foreach (XElement xEl in xDoc.Root.Elements())
                {
                    if (xEl.Element("Estado").Value == pEstado)
                    {
                        Error err = new Error();
                        err.Id = long.Parse(xEl.Attribute("Id").Value);
                        err.Aplicacion = AplicacionXMLManager.getInstancia().getAplicacionById(long.Parse(xEl.Element("Aplicacion").Value));
                        err.Modulo = ModuloXMLManager.getInstancia().getModuloById(long.Parse(xEl.Element("Modulo").Value));
                        err.Descripcion = "" + xEl.Element("Descripcion").Value;
                        err.Estado = (tipoEstado)Enum.Parse(typeof(tipoEstado), "" + xEl.Element("Estado").Value);
                        err.Importancia = (tipoImportancia)Enum.Parse(typeof(tipoImportancia), "" + xEl.Element("Importancia").Value);
                        err.Usuario = UsuarioXMLManager.getInstancia().getUsuarioById(long.Parse(xEl.Element("Usuario").Value));
                        err.FechaCreado = DateTime.Parse(xEl.Element("FechaCreado").Value);
                        if (xEl.Element("FechaCerrado").Value != "")
                        {
                            err.FechaCerrado = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                        }
                        errLst.Add(err);
                    }
                }
            }

            catch (InvalidOperationException)
            {
                errLst = null;
            }
            return errLst;
        }
        public List<Error> getListByAppId(long pAppId)
        {
            /*
             * Devuelve una lista de errores dado el Id de una aplicacion.
             */
            List<Error> errLst = new List<Error>();
            XDocument xDoc = loadDoc();
            try
            {
                foreach (XElement xEl in xDoc.Root.Elements())
                {
                    if (long.Parse(xEl.Element("Aplicacion").Value) == pAppId)
                    {
                        Error err = new Error();
                        err.Id = long.Parse(xEl.Attribute("Id").Value);
                        err.Aplicacion = AplicacionXMLManager.getInstancia().getAplicacionById(long.Parse(xEl.Element("Aplicacion").Value));
                        err.Modulo = ModuloXMLManager.getInstancia().getModuloById(long.Parse(xEl.Element("Modulo").Value));
                        err.Descripcion = "" + xEl.Element("Descripcion").Value;
                        err.Estado = (tipoEstado)Enum.Parse(typeof(tipoEstado), "" + xEl.Element("Estado").Value);
                        err.Importancia = (tipoImportancia)Enum.Parse(typeof(tipoImportancia), "" + xEl.Element("Importancia").Value);
                        err.Usuario = UsuarioXMLManager.getInstancia().getUsuarioById(long.Parse(xEl.Element("Usuario").Value));
                        err.FechaCreado = DateTime.Parse(xEl.Element("FechaCreado").Value);
                        if (xEl.Element("FechaCerrado").Value != "")
                        {
                            err.FechaCerrado = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                        }
                        errLst.Add(err);
                    }
                }
            }

            catch (InvalidOperationException)
            {
                errLst = null;
            }
            return errLst;
        }
        public List<Error> getListByModId(long pModId)
        {
            /*
             * Devuelve una lista de errores dado el Id de un modulo de una aplicacion.
             */
            List<Error> errLst = new List<Error>();
            XDocument xDoc = loadDoc();
            try
            {
                foreach (XElement xEl in xDoc.Root.Elements())
                {
                    if (long.Parse(xEl.Element("Modulo").Value) == pModId)
                    {
                        Error err = new Error();
                        err.Id = long.Parse(xEl.Attribute("Id").Value);
                        err.Aplicacion = AplicacionXMLManager.getInstancia().getAplicacionById(long.Parse(xEl.Element("Aplicacion").Value));
                        err.Modulo = ModuloXMLManager.getInstancia().getModuloById(long.Parse(xEl.Element("Modulo").Value));
                        err.Descripcion = "" + xEl.Element("Descripcion").Value;
                        err.Estado = (tipoEstado)Enum.Parse(typeof(tipoEstado), "" + xEl.Element("Estado").Value);
                        err.Importancia = (tipoImportancia)Enum.Parse(typeof(tipoImportancia), "" + xEl.Element("Importancia").Value);
                        err.Usuario = UsuarioXMLManager.getInstancia().getUsuarioById(long.Parse(xEl.Element("Usuario").Value));
                        err.FechaCreado = DateTime.Parse(xEl.Element("FechaCreado").Value);
                        if (xEl.Element("FechaCerrado").Value != "")
                        {
                            err.FechaCerrado = DateTime.Parse(xEl.Element("FechaCerrado").Value);
                        }
                        errLst.Add(err);
                    }
                }
            }

            catch (InvalidOperationException)
            {
                errLst = null;
            }
            return errLst;
        }
        public List<float> getEstadisticaByAppId(long pAppId, string pEstado)
        {
            /*
             * Recibe un Id de una aplicacion y un estado del error.
             * Devuelve una lista con cuatro valores, el primero es la cantidad de errores, el segundo, el tercero y el cuarto valor,
             * son los porcentajes de los errores por su importancia: baja, media y alta respectivamente.
             */
            List<float> errLst = new List<float>();
            XDocument xDoc = loadDoc();
            float baja = 0;
            float media = 0;
            float alta = 0;
            float total = 0;
            try
            {
                foreach (XElement xEl in xDoc.Root.Elements())
                {
                    if (long.Parse(xEl.Element("Aplicacion").Value) == pAppId && "" + xEl.Element("Estado").Value == pEstado)
                    {
                        total++;
                        switch ("" + xEl.Element("Importancia").Value)
                        { 
                            case "Baja":
                                baja++;
                                break;
                            case "Media":
                                media++;
                                break;
                            case "Alta":
                                alta++;
                                break;
                        }
                    }
                }

                errLst.Add(total);
                errLst.Add((baja != 0) ? (baja * 100 / total) : 0);
                errLst.Add((media != 0) ? (media * 100 / total) : 0);
                errLst.Add((alta != 0) ? (alta * 100 / total) : 0);
                return errLst;
            }

            catch (InvalidOperationException)
            {
                errLst = null;
            }
            return errLst;
        }
       /*
        public List<long> getErroresByModId(long comId)
        {
            
            List<long> lstComments = new List<long>();
            XDocument xDoc = loadDoc();
            foreach (XElement xe in xDoc.Root.Elements())
            {
                if (long.Parse(xe.Element("IdAplicacion").Value) == comId)
                {
                    lstComments.Add(long.Parse(xe.Attribute("Id").Value));
                }
            }
            return lstComments;
        }*/
    }
}